import * as fs from 'fs';
import * as path from 'path';

export interface MethodSignature {
  name: string;
  returnType: string;
  parameters: string;
  modifiers: string[];
  fullSignature: string;
  isAbstract?: boolean;
}

export interface CommonMethod {
  signature: MethodSignature;
  implementations: Array<{
    className: string;
    filePath: string;
    methodBody: string;
  }>;
}

export interface ExtractResult {
  success: boolean;
  message: string;
  extractedInterface?: string;
  interfaceFile?: string;
  abstractClass?: string;
  abstractClassFile?: string;
  commonMethods: CommonMethod[];
  updatedClasses: Array<{
    className: string;
    filePath: string;
    originalExtends?: string;
    newImplements?: string;
    newExtends?: string;
  }>;
  refactorDetails?: string[];
  errors?: string[];
}

/**
 * 抽象类/接口提取重构器 - 从多个相似类中提取公共接口或抽象类
 * 功能：分析多个类的公共方法，生成接口或抽象类，更新类声明
 */
export class AbstractInterfaceExtractor {

  async extractInterface(
    classFiles: string[],
    interfaceName: string,
    projectPath: string,
    outputDir?: string
  ): Promise<ExtractResult> {
    const result: ExtractResult = {
      success: false,
      message: '',
      commonMethods: [],
      updatedClasses: [],
      refactorDetails: [],
      errors: []
    };

    try {
      console.error(`[AbstractInterfaceExtractor] 开始接口提取重构`);
      console.error(`[AbstractInterfaceExtractor] 分析 ${classFiles.length} 个类文件`);
      
      if (classFiles.length < 2) {
        result.errors?.push('至少需要2个类文件才能提取公共接口');
        result.message = '至少需要2个类文件才能提取公共接口';
        return result;
      }

      // 分析每个类的方法
      const classAnalysis: Array<{
        className: string;
        filePath: string;
        methods: MethodSignature[];
        content: string;
      }> = [];

      for (const filePath of classFiles) {
        if (!fs.existsSync(filePath)) {
          result.errors?.push(`文件不存在: ${filePath}`);
          continue;
        }

        const content = fs.readFileSync(filePath, 'utf-8');
        const className = this.extractClassName(content);
        const methods = this.extractPublicMethods(content);

        if (className) {
          classAnalysis.push({
            className,
            filePath,
            methods,
            content
          });
        }
      }

      console.error(`[AbstractInterfaceExtractor] 成功分析 ${classAnalysis.length} 个类`);

      // 找到公共方法
      const commonMethods = this.findCommonMethods(classAnalysis);
      console.error(`[AbstractInterfaceExtractor] 找到 ${commonMethods.length} 个公共方法`);

      if (commonMethods.length === 0) {
        result.success = true;
        result.message = '没有找到公共方法，无需提取接口';
        return result;
      }

      // 生成接口
      const interfaceContent = this.generateInterface(interfaceName, commonMethods, classAnalysis[0].content);
      
      // 确定输出目录
      const targetDir = outputDir || path.dirname(classAnalysis[0].filePath);
      const interfaceFile = path.join(targetDir, `${interfaceName}.java`);

      // 写入接口文件
      fs.writeFileSync(interfaceFile, interfaceContent, 'utf-8');
      result.interfaceFile = interfaceFile;
      result.extractedInterface = interfaceContent;
      result.refactorDetails?.push(`创建接口文件: ${interfaceFile}`);

      // 更新类声明
      for (const classInfo of classAnalysis) {
        try {
          const updatedContent = this.updateClassToImplementInterface(
            classInfo.content,
            interfaceName
          );
          
          fs.writeFileSync(classInfo.filePath, updatedContent, 'utf-8');
          
          result.updatedClasses.push({
            className: classInfo.className,
            filePath: classInfo.filePath,
            newImplements: interfaceName
          });
          
          result.refactorDetails?.push(`更新类实现: ${classInfo.className} implements ${interfaceName}`);
        } catch (error) {
          result.errors?.push(`更新类失败 ${classInfo.className}: ${error}`);
        }
      }

      result.commonMethods = commonMethods;
      result.success = true;
      result.message = `成功提取接口 ${interfaceName}，包含 ${commonMethods.length} 个公共方法`;

    } catch (error) {
      result.errors?.push(`接口提取失败: ${error}`);
      result.message = `接口提取失败: ${error}`;
      console.error(`[AbstractInterfaceExtractor] 错误:`, error);
    }

    return result;
  }

  async extractAbstractClass(
    classFiles: string[],
    abstractClassName: string,
    projectPath: string,
    outputDir?: string
  ): Promise<ExtractResult> {
    const result: ExtractResult = {
      success: false,
      message: '',
      commonMethods: [],
      updatedClasses: [],
      refactorDetails: [],
      errors: []
    };

    try {
      console.error(`[AbstractInterfaceExtractor] 开始抽象类提取重构`);
      console.error(`[AbstractInterfaceExtractor] 分析 ${classFiles.length} 个类文件`);
      
      if (classFiles.length < 2) {
        result.errors?.push('至少需要2个类文件才能提取抽象类');
        result.message = '至少需要2个类文件才能提取抽象类';
        return result;
      }

      // 类似接口提取，但生成抽象类
      const classAnalysis: Array<{
        className: string;
        filePath: string;
        methods: MethodSignature[];
        content: string;
      }> = [];

      for (const filePath of classFiles) {
        if (!fs.existsSync(filePath)) {
          result.errors?.push(`文件不存在: ${filePath}`);
          continue;
        }

        const content = fs.readFileSync(filePath, 'utf-8');
        const className = this.extractClassName(content);
        const methods = this.extractPublicMethods(content);

        if (className) {
          classAnalysis.push({
            className,
            filePath,
            methods,
            content
          });
        }
      }

      // 找到公共方法和可以抽象的方法
      const commonMethods = this.findCommonMethods(classAnalysis);
      const abstractMethods = this.findAbstractMethods(classAnalysis);

      console.error(`[AbstractInterfaceExtractor] 找到 ${commonMethods.length} 个公共方法, ${abstractMethods.length} 个抽象方法`);

      // 生成抽象类
      const abstractClassContent = this.generateAbstractClass(
        abstractClassName, 
        commonMethods, 
        abstractMethods,
        classAnalysis[0].content
      );
      
      const targetDir = outputDir || path.dirname(classAnalysis[0].filePath);
      const abstractClassFile = path.join(targetDir, `${abstractClassName}.java`);

      fs.writeFileSync(abstractClassFile, abstractClassContent, 'utf-8');
      result.abstractClassFile = abstractClassFile;
      result.abstractClass = abstractClassContent;
      result.refactorDetails?.push(`创建抽象类文件: ${abstractClassFile}`);

      // 更新类声明为继承抽象类
      for (const classInfo of classAnalysis) {
        try {
          const updatedContent = this.updateClassToExtendAbstract(
            classInfo.content,
            abstractClassName,
            commonMethods
          );
          
          fs.writeFileSync(classInfo.filePath, updatedContent, 'utf-8');
          
          result.updatedClasses.push({
            className: classInfo.className,
            filePath: classInfo.filePath,
            newExtends: abstractClassName
          });
          
          result.refactorDetails?.push(`更新类继承: ${classInfo.className} extends ${abstractClassName}`);
        } catch (error) {
          result.errors?.push(`更新类失败 ${classInfo.className}: ${error}`);
        }
      }

      result.commonMethods = [...commonMethods, ...abstractMethods];
      result.success = true;
      result.message = `成功提取抽象类 ${abstractClassName}`;

    } catch (error) {
      result.errors?.push(`抽象类提取失败: ${error}`);
      result.message = `抽象类提取失败: ${error}`;
      console.error(`[AbstractInterfaceExtractor] 错误:`, error);
    }

    return result;
  }

  private extractPublicMethods(content: string): MethodSignature[] {
    const methods: MethodSignature[] = [];
    
    // 匹配public方法的正则表达式
    const methodPattern = /^\s*public\s+(?:static\s+)?(?:final\s+)?(?:<[^>]+>\s+)?(\w+(?:<[^>]+>)?(?:\[\])*)\s+(\w+)\s*\(([^)]*)\)\s*(?:throws\s+[^{]+)?\s*\{/gm;
    
    let match;
    while ((match = methodPattern.exec(content)) !== null) {
      const [fullMatch, returnType, methodName, parameters] = match;
      
      // 跳过构造函数
      if (methodName === this.extractClassName(content)) {
        continue;
      }

      // 提取修饰符
      const modifiers = this.extractModifiers(fullMatch);
      
      methods.push({
        name: methodName,
        returnType: returnType.trim(),
        parameters: parameters.trim(),
        modifiers,
        fullSignature: fullMatch.trim()
      });
    }

    return methods;
  }

  private extractModifiers(methodSignature: string): string[] {
    const modifiers: string[] = [];
    
    if (methodSignature.includes('public')) modifiers.push('public');
    if (methodSignature.includes('static')) modifiers.push('static');
    if (methodSignature.includes('final')) modifiers.push('final');
    if (methodSignature.includes('abstract')) modifiers.push('abstract');
    
    return modifiers;
  }

  private findCommonMethods(classAnalysis: Array<{ className: string; methods: MethodSignature[]; }>) {
    const commonMethods: CommonMethod[] = [];
    
    if (classAnalysis.length === 0) return commonMethods;
    
    const firstClassMethods = classAnalysis[0].methods;
    
    for (const method of firstClassMethods) {
      // 检查是否在所有类中都存在相同签名的方法
      const isCommon = classAnalysis.every(classInfo => 
        classInfo.methods.some(m => this.isMethodSignatureCompatible(method, m))
      );
      
      if (isCommon) {
        const implementations = classAnalysis.map(classInfo => ({
          className: classInfo.className,
          filePath: (classInfo as any).filePath || '',
          methodBody: this.extractMethodBody((classInfo as any).content || '', method.name)
        }));
        
        commonMethods.push({
          signature: method,
          implementations
        });
      }
    }
    
    return commonMethods;
  }

  private findAbstractMethods(classAnalysis: Array<{ className: string; methods: MethodSignature[]; }>) {
    // 找到可以抽象化的方法（签名相同但实现不同的方法）
    const abstractMethods: CommonMethod[] = [];
    
    // 这里简化实现，实际可以分析方法体的相似性
    return abstractMethods;
  }

  private isMethodSignatureCompatible(method1: MethodSignature, method2: MethodSignature): boolean {
    return method1.name === method2.name &&
           method1.returnType === method2.returnType &&
           this.normalizeParameters(method1.parameters) === this.normalizeParameters(method2.parameters);
  }

  private normalizeParameters(parameters: string): string {
    // 标准化参数字符串，移除多余空格
    return parameters.replace(/\s+/g, ' ').trim();
  }

  private generateInterface(interfaceName: string, commonMethods: CommonMethod[], sampleContent: string): string {
    const packageName = this.extractPackageName(sampleContent);
    
    let interfaceContent = '';
    
    // 包声明
    if (packageName) {
      interfaceContent += `package ${packageName};\n\n`;
    }

    // 接口声明
    interfaceContent += `/**\n`;
    interfaceContent += ` * 公共接口 - 自动提取生成\n`;
    interfaceContent += ` */\n`;
    interfaceContent += `public interface ${interfaceName} {\n\n`;

    // 方法声明
    for (const commonMethod of commonMethods) {
      const method = commonMethod.signature;
      interfaceContent += `    ${method.returnType} ${method.name}(${method.parameters});\n\n`;
    }

    interfaceContent += '}\n';
    return interfaceContent;
  }

  private generateAbstractClass(
    className: string, 
    commonMethods: CommonMethod[], 
    abstractMethods: CommonMethod[],
    sampleContent: string
  ): string {
    const packageName = this.extractPackageName(sampleContent);
    
    let classContent = '';
    
    // 包声明
    if (packageName) {
      classContent += `package ${packageName};\n\n`;
    }

    // 抽象类声明
    classContent += `/**\n`;
    classContent += ` * 抽象基类 - 自动提取生成\n`;
    classContent += ` */\n`;
    classContent += `public abstract class ${className} {\n\n`;

    // 公共方法实现（如果有相同实现）
    for (const commonMethod of commonMethods) {
      const method = commonMethod.signature;
      const firstImpl = commonMethod.implementations[0];
      
      // 检查是否所有实现都相同
      const allSame = commonMethod.implementations.every(impl => 
        impl.methodBody === firstImpl.methodBody
      );
      
      if (allSame && firstImpl.methodBody) {
        classContent += `    public ${method.returnType} ${method.name}(${method.parameters}) {\n`;
        classContent += `        ${firstImpl.methodBody}\n`;
        classContent += `    }\n\n`;
      } else {
        // 抽象方法
        classContent += `    public abstract ${method.returnType} ${method.name}(${method.parameters});\n\n`;
      }
    }

    // 纯抽象方法
    for (const abstractMethod of abstractMethods) {
      const method = abstractMethod.signature;
      classContent += `    public abstract ${method.returnType} ${method.name}(${method.parameters});\n\n`;
    }

    classContent += '}\n';
    return classContent;
  }

  private updateClassToImplementInterface(content: string, interfaceName: string): string {
    // 更新类声明以实现接口
    const classDeclarationPattern = /^(\s*public\s+class\s+\w+)(\s+extends\s+\w+)?(\s+implements\s+[^{]+)?(\s*\{)/m;
    
    return content.replace(classDeclarationPattern, (match, classDecl, extendsClause, implementsClause, openBrace) => {
      let newDeclaration = classDecl;
      
      if (extendsClause) {
        newDeclaration += extendsClause;
      }
      
      if (implementsClause) {
        // 已有implements，添加新接口
        newDeclaration += implementsClause.replace(/\s*\{$/, '') + ', ' + interfaceName;
      } else {
        // 没有implements，添加
        newDeclaration += ' implements ' + interfaceName;
      }
      
      return newDeclaration + openBrace;
    });
  }

  private updateClassToExtendAbstract(
    content: string, 
    abstractClassName: string,
    commonMethods: CommonMethod[]
  ): string {
    // 更新类声明以继承抽象类
    const classDeclarationPattern = /^(\s*public\s+class\s+\w+)(\s+extends\s+\w+)?(\s+implements\s+[^{]+)?(\s*\{)/m;
    
    let updatedContent = content.replace(classDeclarationPattern, (match, classDecl, extendsClause, implementsClause, openBrace) => {
      let newDeclaration = classDecl + ' extends ' + abstractClassName;
      
      if (implementsClause) {
        newDeclaration += implementsClause;
      }
      
      return newDeclaration + openBrace;
    });

    // 移除已在抽象类中实现的公共方法
    for (const commonMethod of commonMethods) {
      const methodName = commonMethod.signature.name;
      const methodPattern = new RegExp(
        `\\s*public\\s+[^{]*\\b${methodName}\\s*\\([^)]*\\)\\s*\\{[^}]*\\}\\s*`,
        'g'
      );
      updatedContent = updatedContent.replace(methodPattern, '');
    }

    return updatedContent;
  }

  private extractMethodBody(content: string, methodName: string): string {
    // 简化实现：提取方法体
    const pattern = new RegExp(`public\\s+[^{]*\\b${methodName}\\s*\\([^)]*\\)\\s*\\{([^}]*)\\}`, 's');
    const match = content.match(pattern);
    return match ? match[1].trim() : '';
  }

  private extractClassName(content: string): string | null {
    const match = content.match(/(?:public\s+)?(?:class|interface|enum)\s+(\w+)/);
    return match ? match[1] : null;
  }

  private extractPackageName(content: string): string {
    const match = content.match(/package\s+([^;]+);/);
    return match ? match[1].trim() : '';
  }
}